package com.yh.manage.cms.service;

import com.alibaba.fastjson.JSON;
import com.lxw.framework.domain.cms.CmsPage;
import com.lxw.framework.domain.cms.CmsTemplate;
import com.lxw.framework.domain.cms.request.QueryPageRequest;
import com.lxw.framework.domain.cms.response.CmsCode;
import com.lxw.framework.domain.cms.response.CmsPageResult;
import com.lxw.framework.exception.CastException;
import com.lxw.framework.exception.CustomException;
import com.lxw.framework.model.response.CommonCode;
import com.lxw.framework.model.response.QueryResponseResult;
import com.lxw.framework.model.response.QueryResult;
import com.lxw.framework.model.response.ResponseResult;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.yh.manage.cms.config.RabbitmqConfig;
import com.yh.manage.cms.dao.CmsPageRepository;
import com.yh.manage.cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
@Slf4j
public class CmsPageService {

    @Autowired
    private CmsPageRepository cmsPageRepository;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;

    @Autowired
    private RabbitTemplate rabbitTemplate;

  /*  //routingKey 即站点Id
    @Value("${yh.mq.routeKey}")
    public String routingKey;*/


    public QueryResponseResult findCmsPagesBypage(Integer page, Integer size,
                                                  QueryPageRequest queryPageRequest) {
//        List<CmsPage> cmsPageList = cmsPageRepository.findAll();

        if (page <= 0) {
            page = 1;
        }
        page = page-1;//为了适应mongodb的接口将页码减1 if (size <= 0)
        //设置分页
        Pageable pageable = PageRequest.of(page, size);

        //创建存放匹配规则的对象
        ExampleMatcher exampleMatcher = ExampleMatcher.matching();
        //创建值对象
        CmsPage cmsPage = new CmsPage();
        if(org.apache.commons.lang3.StringUtils.isNotEmpty(queryPageRequest.getPageAliase())){
          cmsPage.setPageAliase(queryPageRequest.getPageAliase());
            exampleMatcher= exampleMatcher.withMatcher("pageAliase",ExampleMatcher.GenericPropertyMatchers.contains());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getTemplateId())){
            cmsPage.setTemplateId(queryPageRequest.getTemplateId());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getSiteId())){
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }
        Example<CmsPage> cmsPageExample = Example.of(cmsPage, exampleMatcher);
        //分页查询
        Page<CmsPage> cmsPages = cmsPageRepository.findAll(pageable);
        //获取分页结果集
        List<CmsPage> cmsPageList = cmsPages.getContent();
        //获取总条数
        long totalElements = cmsPages.getTotalElements();
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(cmsPageList);
        queryResult.setTotal(totalElements);
        QueryResponseResult result = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
        return result;
    }
    //添加页面
    public CmsPageResult addCmsPage(CmsPage cmsPage) {
        if(cmsPage == null){
            CastException.cast(CommonCode.VALIDATA);
//            throw new CustomException(CommonCode.VALIDATA);
//            return new CmsPageResult(CommonCode.FAIL,null);
      }
        //校验页面是否存在，根据页面名称、站点Id、页面webpath查询CmsPage
        CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId()
                , cmsPage.getPageWebPath());
        if (cmsPage1 == null){
            cmsPageRepository.insert(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
        }else {
           throw new CustomException(CommonCode.CONNECTION_DB);
        }
    }

    public CmsPageResult findCmsPageById(String pageId) {
        Optional<CmsPage> cmsPageOptional = cmsPageRepository.findById(pageId);
        if (cmsPageOptional.isPresent()) {
            return new CmsPageResult(CommonCode.SUCCESS,cmsPageOptional.get());
        }
        return new CmsPageResult(CommonCode.FAIL,null);
    }

    public CmsPageResult updateCmsPage(String pageId, CmsPage cmsPage) {
        if(StringUtils.isEmpty(pageId) || cmsPage ==null){
            return new CmsPageResult(CommonCode.FAIL,null);
        }
        cmsPage.setPageId(pageId);
        CmsPage cmsPage1 = cmsPageRepository.save(cmsPage);
        return new CmsPageResult(CommonCode.SUCCESS,cmsPage1);
    }

    public ResponseResult delCmsPageById(String pageId) {
        if(StringUtils.isEmpty(pageId)){
            return new ResponseResult(CommonCode.FAIL);
        }
        Integer res = cmsPageRepository.deleteByPageId(pageId);
        if (res>0){
            return new ResponseResult(CommonCode.SUCCESS);
        }
        return new ResponseResult(CommonCode.FAIL);
    }
    //生成静态html根据cmsPageId
    public String  getHtmlPageById(String pageId){
        if(StringUtils.isEmpty(pageId)){
            CastException.cast(CommonCode.VALIDATA);
        }

        //根据Id获取CmsPage对象
        Optional<CmsPage> cmsPageOptional = cmsPageRepository.findById(pageId);
        if(!cmsPageOptional.isPresent()){
            CastException.cast(CommonCode.VALIDATA);
        }
        CmsPage cmsPage = cmsPageOptional.get();
        String dataUrl = cmsPage.getDataUrl();
        String templateId = cmsPage.getTemplateId();

        //获取模型数据
        Map modelData = this.getModelData(dataUrl);

        //获取模板
        String templateContent = this.getTemplateByTempateId(templateId);

        //通过Freemarker把模型数据渲染到模板上生成静态html页面
        String html = this.gericHtml(modelData, templateContent);
        return html;
    }
    //通过Freemarker把模型数据渲染到模板上生成静态html页面
    private String gericHtml(Map modelData,String templateContent){

        //创建configuration配置对象
        Configuration configuration = new Configuration(Configuration.getVersion());

        //设置模块编码
        configuration.setDefaultEncoding("utf-8");

        //创建String字符串模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateContent);

        //把字符串模板加载器放入Configuration对象
        configuration.setTemplateLoader(stringTemplateLoader);

        //获取模板对象
        try {
            Template template = configuration.getTemplate("template");
            String htmlContent = FreeMarkerTemplateUtils
                    .processTemplateIntoString(template, modelData);
            return htmlContent;
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
           return null;
    }
    //获取模板
    private String getTemplateByTempateId(String templateId){
        if (StringUtils.isEmpty(templateId)) {
            CastException.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
       //根据模板id获取模板对象
        Optional<CmsTemplate> cmsTemplateOptional = cmsTemplateRepository.findById(templateId);
        //判断cmsTemplateOptional对象是否存在
        if (!cmsTemplateOptional.isPresent()){
            CastException.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        CmsTemplate cmsTemplate = cmsTemplateOptional.get();
        //获取模板文件id
        String templateFileId = cmsTemplate.getTemplateFileId();

        //根据模板文件id查询模板是否存在
        GridFSFile gridFSFile = gridFsTemplate
                .findOne(Query.query(Criteria.where("_id").is(templateFileId)));
        //打开下载流
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket
                .openDownloadStream(gridFSFile.getObjectId());

        //操作下载流
        GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);        //从操作流中获取信息
        try {
            InputStream inputStream = gridFsResource.getInputStream();
            String ftlContent = IOUtils.toString(inputStream, "utf-8");
            inputStream.close();
            return ftlContent;
        } catch (IOException e) {
            log.error("下载模板异常:{}",e.getMessage());
            e.printStackTrace();
        }

        return null;
    }
    //获取模型数据
    private Map getModelData(String dataUrl){
        if(StringUtils.isEmpty(dataUrl)){
            CastException.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }

        ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = entity.getBody();
        return body;
    }

    public ResponseResult postPage(String pageId) {
        //
        Optional<CmsPage> cmsPageOptional = cmsPageRepository.findById(pageId);
        if(!cmsPageOptional.isPresent()){
            CastException.cast(CmsCode.CMS_PAGE_EXISTSID);
        }
        CmsPage cmsPage = cmsPageOptional.get();
        //生成静态html页面
        String htmlContent = this.getHtmlPageById(pageId);
        InputStream inputStream = null;
        try {
            inputStream = IOUtils.toInputStream(htmlContent, "utf-8");
            //把静态html存放到gridFs上
            ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
            cmsPage.setHtmlFileId(objectId.toHexString());
            //
            cmsPageRepository.save(cmsPage);
            //发送消息
            this.sendMsg(pageId,cmsPage.getSiteId());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return new ResponseResult(CommonCode.FAIL);
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error(e.getMessage());
                return new ResponseResult(CommonCode.FAIL);
            }
        }
        return new ResponseResult(CommonCode.SUCCESS);
    }
    private void sendMsg(String pageId,String siteId){
        Map<String,String> map = new HashMap<>();
        map.put("pageId",pageId);
        String msg = JSON.toJSONString(map);
        //发送消息
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,siteId,msg);
    }

    public CmsPageResult saveCmsPage(CmsPage cmsPage) {
        if(cmsPage == null
                || StringUtils.isEmpty(cmsPage.getPageName())
                || StringUtils.isEmpty(cmsPage.getPageWebPath())
                || StringUtils.isEmpty(cmsPage.getSiteId())
                ){
            CastException.cast(CommonCode.VALIDATA);
        }

        CmsPage cmsPageDb = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName()
                , cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if(cmsPageDb !=null){
            cmsPage.setPageId(cmsPageDb.getPageId());
            cmsPageRepository.save(cmsPage);
        }else {
            cmsPageRepository.insert(cmsPage);
        }
        return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
    }

    //一键发布页面
    public ResponseResult postPageQuick(CmsPage cmsPage) {
        //保存或更新CmsPage信息
        CmsPageResult cmsPageResult = this.saveCmsPage(cmsPage);
        if(!cmsPageResult.isSuccess()){
            CastException.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
        }
        CmsPage cmsPageDb = cmsPageResult.getCmsPage();
        //发布页面
        ResponseResult responseResult = this.postPage(cmsPageDb.getPageId());
        return responseResult;
    }
}
